//
// Created by 乐亦聪 on 15/5/20.
//

#ifndef UNTITLED_INC_H
#define UNTITLED_INC_H

#define SYNCED(x) {\
    pthread_mutex_lock( &sum_mutex );\
    x;\
    pthread_mutex_unlock( &sum_mutex );\
}

enum Direction {
    TOP = 0,
    DOWN = 1,
    LEFT = 2,
    RIGHT = 3,
    TOPLEFT = 4,
    TOPRIGHT = 5,
    DOWNLEFT = 6,
    DOWNRIGHT = 7
};

enum Faction {
    F1 = 1,
    F2 = 2,
    None = 0
};

typedef unsigned int Board[5];

struct Game {
    int spacer_s1 = 0;
    Board board;
    int records[640];
    int step = 0;
    int steps = 0;
    int action;
    int spacer_s3 = 0;
    Board capable;
    int f1 = 2;
    int f2 = 2;
    int c1 = 4;
    int c2 = 4;
    int capableCache[28];
    int (*players[2])(Game game, Faction f, int*);
};

const int directionX[9] = {-1, 1,  0, 0, -1, -1,  1, 1, 0};

const int directionY[9] = { 0, 0, -1, 1, -1,  1, -1, 1, 0};

const int factionOffset[8] = {0, 0, 0, 2, 1, 3, 0, 0};

const int factionValues[8] = {0, 0, 1, 0, 0, 1, 1, 1};

const Faction factions[2] = {F1, F2};

int capable[64] = {
        0b10001010,
        0b11001110,
        0b11001110,
        0b11001110,
        0b11001110,
        0b11001110,
        0b11001110,
        0b01000110,
        0b10101011,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b01010111,
        0b10101011,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b01010111,
        0b10101011,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b01010111,
        0b10101011,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b01010111,
        0b10101011,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b01010111,
        0b10101011,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b11111111,
        0b01010111,
        0b00101001,
        0b00111101,
        0b00111101,
        0b00111101,
        0b00111101,
        0b00111101,
        0b00111101,
        0b00010101
};

#define CAN_MOVE(i, d) COUNT_1_INT(capable[i] & (1 << d))

#define DX(x) directionX[x]
#define DY(x) directionY[x]
#define FV(x) factionValues[x]
#define FOFF(x) (factionOffset[x])

#define GET_BIT_AT(x, y) (!!(x & (1 << (31 - y))))
#define SET_BIT_AT(x, v, n) ;(x = (x | (1 << (31 - n))) & ((v << (31 - n)) | ((~0) ^ (1 << (31 - n)))));
#define COUNT_1_INT(x) popcnt(x)
#define COUNT_0_INT(x) (32 - COUNT_1_INT(x))

#define MATRIX_OFF(x, y) (x * MATRIX_WIDTH + y)

//p: panel, 0/1
#define GET_BIT_ONPANEL_BYOFF(b, p, o) GET_BIT_AT(b[2 * p +o / 32], o % 32)
#define GET_BIT_ONPANEL(b, p, x, y) GET_BIT_ONPANEL_BYOFF(b, p, MATRIX_OFF(x, y))
#define GET_FACTION_AT(b, x, y) (GET_BIT_ONPANEL(b, 0, x, y) + (GET_BIT_ONPANEL(b, 1, x, y) << 1))
#define SET_BIT_ONPANEL_BYOFF(b, p, o, v) ;SET_BIT_AT(b[2 * p + o / 32], v, (o % 32));
#define SET_BIT_ONPANEL(b, p, x, y, v) SET_BIT_ONPANEL_BYOFF(b, p, MATRIX_OFF(x, y), v)
#define SET_FACTION_AT(b, x, y, f) SET_BIT_ONPANEL(b, 0, x, y, FV(f * 2));\
                                   SET_BIT_ONPANEL(b, 1, x, y, FV(f * 2 + 1));

#define FACTION_CNT(b, f) (COUNT_1_INT(b[FOFF(f * 2)]) + COUNT_1_INT(b[FOFF(f * 2 + 1)]))

#define EMPTYSLOTS_ONBOARD(b) (COUNT_0_INT(b[0] | b[2]) + COUNT_0_INT(b[1] | b[3]))

int randomGameSelectorBot(Game game, Faction f, int*cache);
void printBoard(Board board);

int popcnt(int i) {
    i = i - ((i >> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
    return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}

int nextInt(int cap) {
    return cap == 1 ? 1 : 1 + rand() % (cap - 1);
}

#endif //UNTITLED_INC_H
